#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
键盘识别检测系统 - 工业质检工具
重建版本 - 清理代码结构，优化功能
"""

import cv2
import numpy as np
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk
import threading
import queue
import time
import logging
from datetime import datetime
import os
from typing import Tuple, List, Dict, Optional

class KeyboardInspector:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("键盘识别检测系统 - 工业质检工具 v2.0")
        self.root.geometry("1600x900")
        
        # 初始化变量
        self.reference_image = None
        self.corrected_reference_image = None
        self.reference_rotation = 0.0
        self.reference_characters = []  # 参考键盘字符
        self.camera_active = False
        self.cap = None
        self.detection_active = False
        self.log_queue = queue.Queue()
        self.last_detection_time = 0
        self.detection_interval = 2.0  # 检测间隔（秒）
        
        # 检测模式
        self.character_detection_mode = True  # 启用字符检测模式
        
        # 设置日志
        self.setup_logging()
        
        # 创建GUI
        self.create_gui()
        
        # 启动日志更新线程
        self.start_log_updater()
        
    def setup_logging(self):
        """设置日志系统"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.StreamHandler(),
                logging.FileHandler('keyboard_inspector.log', encoding='utf-8')
            ]
        )
        self.logger = logging.getLogger(__name__)
        
    def create_gui(self):
        """创建用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title_label = ttk.Label(main_frame, text="键盘识别检测系统 - 工业质检工具", 
                               font=("Arial", 16, "bold"))
        title_label.pack(pady=(0, 10))
        
        # 控制面板
        control_frame = ttk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 图像加载按钮
        ttk.Button(control_frame, text="加载参考图像", 
                  command=self.load_reference_image).pack(side=tk.LEFT, padx=(0, 10))
        
        # 摄像头控制按钮
        ttk.Button(control_frame, text="启动摄像头", 
                  command=self.start_camera).pack(side=tk.LEFT, padx=(0, 10))
        
        ttk.Button(control_frame, text="停止摄像头", 
                  command=self.stop_camera).pack(side=tk.LEFT, padx=(0, 10))
        
        # 检测模式选择
        mode_frame = ttk.Frame(control_frame)
        mode_frame.pack(side=tk.LEFT, padx=(20, 0))
        
        ttk.Label(mode_frame, text="检测模式:").pack(side=tk.LEFT)
        
        self.detection_mode_var = tk.StringVar(value="character")
        char_mode_radio = ttk.Radiobutton(mode_frame, text="字符检测", variable=self.detection_mode_var, 
                                        value="character", command=self.toggle_detection_mode)
        char_mode_radio.pack(side=tk.LEFT, padx=(5, 10))
        
        pixel_mode_radio = ttk.Radiobutton(mode_frame, text="像素检测", variable=self.detection_mode_var, 
                                         value="pixel", command=self.toggle_detection_mode)
        pixel_mode_radio.pack(side=tk.LEFT)
        
        # 检测控制按钮
        ttk.Button(control_frame, text="单次检测", 
                  command=self.single_detection).pack(side=tk.LEFT, padx=(20, 10))
        
        ttk.Button(control_frame, text="开始连续检测", 
                  command=self.start_detection).pack(side=tk.LEFT, padx=(0, 10))
        
        ttk.Button(control_frame, text="停止检测", 
                  command=self.stop_detection).pack(side=tk.LEFT, padx=(0, 10))
        
        # 清空日志按钮
        ttk.Button(control_frame, text="清空日志", 
                  command=self.clear_log).pack(side=tk.LEFT, padx=(20, 0))
        
        # 图像显示区域
        image_frame = ttk.Frame(main_frame)
        image_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 参考图像面板（左侧）
        ref_frame = ttk.LabelFrame(image_frame, text="参考键盘图像（自动摆正）", width=400, height=300)
        ref_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))
        ref_frame.pack_propagate(False)
        
        # 参考图像画布
        self.ref_canvas = tk.Canvas(ref_frame, bg='white')
        self.ref_canvas.pack(fill=tk.BOTH, expand=True)
        
        # 参考图像缩放和平移相关变量
        self.ref_scale = 1.0
        self.ref_offset_x = 0
        self.ref_offset_y = 0
        self.ref_drag_start_x = 0
        self.ref_drag_start_y = 0
        self.ref_is_dragging = False
        
        # 绑定鼠标事件
        self.ref_canvas.bind("<MouseWheel>", self.on_ref_mousewheel)
        self.ref_canvas.bind("<Button-1>", self.on_ref_mouse_press)
        self.ref_canvas.bind("<B1-Motion>", self.on_ref_mouse_drag)
        self.ref_canvas.bind("<ButtonRelease-1>", self.on_ref_mouse_release)
        self.ref_canvas.bind("<Button-3>", self.on_ref_reset_view)  # 右键重置视图
        
        # 校正信息标签
        self.correction_info_label = tk.Label(ref_frame, text="等待加载参考图像...", 
                                            font=("Arial", 9), fg="blue", bg="lightgray")
        self.correction_info_label.pack(pady=5)
        
        # 摄像头图像面板（中间）
        cam_frame = ttk.LabelFrame(image_frame, text="实时摄像头图像", width=400, height=300)
        cam_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 5))
        cam_frame.pack_propagate(False)
        
        self.cam_canvas = tk.Canvas(cam_frame, bg='white')
        self.cam_canvas.pack(fill=tk.BOTH, expand=True)
        
        # 检测结果面板（右侧）
        result_frame = ttk.LabelFrame(image_frame, text="检测结果图像", width=400, height=300)
        result_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))
        result_frame.pack_propagate(False)
        
        self.result_canvas = tk.Canvas(result_frame, bg='white')
        self.result_canvas.pack(fill=tk.BOTH, expand=True)
        
        # 检测结果图像缩放和平移相关变量
        self.result_scale = 1.0
        self.result_offset_x = 0
        self.result_offset_y = 0
        self.result_drag_start_x = 0
        self.result_drag_start_y = 0
        self.result_is_dragging = False
        
        # 绑定鼠标事件
        self.result_canvas.bind("<MouseWheel>", self.on_result_mousewheel)
        self.result_canvas.bind("<Button-1>", self.on_result_mouse_press)
        self.result_canvas.bind("<B1-Motion>", self.on_result_mouse_drag)
        self.result_canvas.bind("<ButtonRelease-1>", self.on_result_mouse_release)
        self.result_canvas.bind("<Button-3>", self.on_result_reset_view)  # 右键重置视图
        
        # 日志输出区域
        log_frame = ttk.LabelFrame(main_frame, text="检测日志")
        log_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建日志文本框和滚动条
        log_text_frame = ttk.Frame(log_frame)
        log_text_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.log_text = tk.Text(log_text_frame, height=8, wrap=tk.WORD)
        scrollbar = ttk.Scrollbar(log_text_frame, orient=tk.VERTICAL, command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=scrollbar.set)
        
        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 配置日志文本标签
        self.log_text.tag_configure("error", foreground="red")
        self.log_text.tag_configure("warning", foreground="orange")
        self.log_text.tag_configure("success", foreground="green")
        self.log_text.tag_configure("info", foreground="blue")
        
    def load_reference_image(self):
        """加载参考键盘图像 - 自动摆正版本"""
        file_path = filedialog.askopenfilename(
            title="选择参考键盘图像",
            filetypes=[
                ("Image files", "*.jpg *.jpeg *.png *.bmp"),
                ("All files", "*.*")
            ]
        )
        
        if file_path:
            try:
                # 加载图像
                image = cv2.imread(file_path)
                if image is not None:
                    self.reference_image = image
                    
                    # 使用改进的检测器
                    from improved_keyboard_detector import ImprovedKeyboardDetector
                    detector = ImprovedKeyboardDetector()
                    
                    # 第一步：自动校正参考图像旋转
                    self.log_message("正在自动摆正参考图像...", "info")
                    corrected_image, rotation_angle, correction_info = detector.auto_correct_reference_image(image)
                    
                    # 保存校正后的图像
                    self.corrected_reference_image = corrected_image
                    self.reference_rotation = rotation_angle
                    
                    # 第二步：在校正后的图像上检测字符
                    if self.character_detection_mode:
                        self.log_message("正在检测参考图像中的字符...", "info")
                        from simple_character_detector import SimpleCharacterDetector
                        char_detector = SimpleCharacterDetector()
                        self.reference_characters = char_detector.detect_keyboard_characters(corrected_image)
                        self.reference_keys = []  # 保持兼容性
                    else:
                        self.log_message("正在检测参考图像中的按键...", "info")
                        self.reference_keys, _, _ = detector.detect_keyboard_keys(corrected_image)
                        self.reference_characters = []
                    
                    # 显示校正后的参考图像
                    self.display_reference_image(corrected_image)
                    
                    # 显示校正信息
                    self.log_message(f"成功加载参考图像: {os.path.basename(file_path)}", "success")
                    if self.character_detection_mode:
                        self.log_message(f"检测到 {len(self.reference_characters)} 个字符按键", "info")
                        # 显示检测到的字符
                        chars = [key.character for key in self.reference_characters]
                        self.log_message(f"检测到的字符: {', '.join(chars[:20])}{'...' if len(chars) > 20 else ''}", "info")
                    else:
                        self.log_message(f"检测到 {len(self.reference_keys)} 个按键", "info")
                    
                    if abs(rotation_angle) > 1:
                        self.log_message(f"参考图像已自动摆正，旋转角度: {rotation_angle:.1f}°", "success")
                        self.log_message(f"校正方法: {correction_info.get('method', 'unknown')}", "info")
                        self.log_message(f"校正置信度: {correction_info.get('confidence', 0):.2f}", "info")
                        
                        # 更新校正信息标签
                        info_text = f"已校正 {rotation_angle:.1f}° | {correction_info.get('method', 'unknown')} | 置信度: {correction_info.get('confidence', 0):.2f}"
                        self.correction_info_label.config(text=info_text, fg="green")
                    else:
                        self.log_message("参考图像无需校正，已处于正确方向", "info")
                        self.correction_info_label.config(text="无需校正，图像已处于正确方向", fg="blue")
                        
                else:
                    self.log_message("无法加载图像文件", "error")
            except Exception as e:
                self.log_message(f"加载图像失败: {str(e)}", "error")
                
    def display_reference_image(self, image):
        """显示参考图像"""
        # 保存原始图像
        self.ref_original_image = image
        
        # 转换图像格式
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        pil_image = Image.fromarray(image_rgb)
        
        # 保存原始PIL图像
        self.ref_pil_image = pil_image
        
        # 重置缩放和平移
        self.ref_scale = 1.0
        self.ref_offset_x = 0
        self.ref_offset_y = 0
        
        # 显示图像
        self._update_reference_display()
    
    def _update_reference_display(self):
        """更新参考图像显示"""
        if not hasattr(self, 'ref_pil_image') or self.ref_pil_image is None:
            return
            
        # 获取画布尺寸
        canvas_width = self.ref_canvas.winfo_width()
        canvas_height = self.ref_canvas.winfo_height()
        
        if canvas_width <= 1 or canvas_height <= 1:
            return
            
        # 计算缩放后的图像尺寸
        img_width, img_height = self.ref_pil_image.size
        scaled_width = int(img_width * self.ref_scale)
        scaled_height = int(img_height * self.ref_scale)
        
        # 调整图像大小
        resized_image = self.ref_pil_image.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
        
        # 转换为Tkinter格式
        self.ref_photo = ImageTk.PhotoImage(resized_image)
        
        # 计算图像在画布中的位置
        x = canvas_width // 2 + self.ref_offset_x
        y = canvas_height // 2 + self.ref_offset_y
        
        # 清除画布并显示图像
        self.ref_canvas.delete("all")
        self.ref_canvas.create_image(x, y, image=self.ref_photo, anchor=tk.CENTER)
        
        # 添加操作提示
        self.ref_canvas.create_text(10, 10, text="鼠标中键: 缩放 | 左键拖拽: 平移 | 右键: 重置", 
                                   anchor=tk.NW, fill="blue", font=("Arial", 8))
    
    def on_ref_mousewheel(self, event):
        """参考图像鼠标滚轮缩放"""
        if not hasattr(self, 'ref_pil_image') or self.ref_pil_image is None:
            return
            
        # 缩放因子
        scale_factor = 1.1 if event.delta > 0 else 0.9
        
        # 限制缩放范围
        new_scale = self.ref_scale * scale_factor
        if 0.1 <= new_scale <= 5.0:
            self.ref_scale = new_scale
            self._update_reference_display()
    
    def on_ref_mouse_press(self, event):
        """参考图像鼠标按下"""
        self.ref_drag_start_x = event.x
        self.ref_drag_start_y = event.y
        self.ref_is_dragging = True
    
    def on_ref_mouse_drag(self, event):
        """参考图像鼠标拖拽"""
        if not self.ref_is_dragging:
            return
            
        # 计算拖拽距离
        dx = event.x - self.ref_drag_start_x
        dy = event.y - self.ref_drag_start_y
        
        # 更新偏移量
        self.ref_offset_x += dx
        self.ref_offset_y += dy
        
        # 更新拖拽起始点
        self.ref_drag_start_x = event.x
        self.ref_drag_start_y = event.y
        
        # 更新显示
        self._update_reference_display()
    
    def on_ref_mouse_release(self, event):
        """参考图像鼠标释放"""
        self.ref_is_dragging = False
    
    def on_ref_reset_view(self, event):
        """参考图像重置视图"""
        self.ref_scale = 1.0
        self.ref_offset_x = 0
        self.ref_offset_y = 0
        self._update_reference_display()
        self.log_message("参考图像视图已重置", "info")
    
    def start_camera(self):
        """启动摄像头"""
        try:
            self.cap = cv2.VideoCapture(0)
            if self.cap.isOpened():
                self.camera_active = True
                self.camera_thread = threading.Thread(target=self.camera_loop, daemon=True)
                self.camera_thread.start()
                self.log_message("摄像头已启动", "success")
            else:
                self.log_message("无法启动摄像头", "error")
        except Exception as e:
            self.log_message(f"启动摄像头失败: {str(e)}", "error")
    
    def stop_camera(self):
        """停止摄像头"""
        self.camera_active = False
        if self.cap:
            self.cap.release()
        self.log_message("摄像头已停止", "info")
    
    def camera_loop(self):
        """摄像头循环线程"""
        while self.camera_active:
            if self.cap and self.cap.isOpened():
                ret, frame = self.cap.read()
                if ret:
                    # 显示摄像头图像
                    self.display_camera_frame(frame)
                    
                    # 如果连续检测激活，进行键盘检测（控制检测频率）
                    if self.detection_active and self.reference_characters:
                        current_time = time.time()
                        if current_time - self.last_detection_time >= self.detection_interval:
                            self.perform_keyboard_detection(frame)
                            self.last_detection_time = current_time
                            
            time.sleep(0.033)  # 约30fps
    
    def display_camera_frame(self, frame):
        """显示摄像头帧"""
        # 转换图像格式
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        pil_image = Image.fromarray(frame_rgb)
        
        # 调整图像大小
        canvas_width = self.cam_canvas.winfo_width()
        canvas_height = self.cam_canvas.winfo_height()
        
        if canvas_width > 1 and canvas_height > 1:
            img_width, img_height = pil_image.size
            scale = min(canvas_width / img_width, canvas_height / img_height)
            
            new_width = int(img_width * scale)
            new_height = int(img_height * scale)
            
            resized_image = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS)
            self.cam_photo = ImageTk.PhotoImage(resized_image)
            
            self.cam_canvas.delete("all")
            self.cam_canvas.create_image(canvas_width//2, canvas_height//2, 
                                       image=self.cam_photo, anchor=tk.CENTER)
    
    def single_detection(self):
        """单次检测"""
        if self.reference_characters is None and self.reference_keys is None:
            self.log_message("请先加载参考键盘图像", "warning")
            return
            
        if not self.camera_active:
            self.log_message("请先启动摄像头", "warning")
            return
            
        # 获取当前摄像头帧
        if self.cap and self.cap.isOpened():
            ret, frame = self.cap.read()
            if ret:
                self.log_message("开始单次检测...", "info")
                # 单次检测不受时间间隔限制
                self.perform_keyboard_detection(frame)
                self.log_message("单次检测完成", "info")
            else:
                self.log_message("无法获取摄像头图像", "error")
        else:
            self.log_message("摄像头未启动", "error")
    
    def start_detection(self):
        """开始连续检测"""
        if not self.camera_active:
            self.log_message("请先启动摄像头", "warning")
            return
            
        self.detection_active = True
        self.log_message("连续检测已启动", "success")
        
    def stop_detection(self):
        """停止检测"""
        self.detection_active = False
        self.log_message("检测已停止", "info")
    
    def toggle_detection_mode(self):
        """切换检测模式"""
        mode = self.detection_mode_var.get()
        self.character_detection_mode = (mode == "character")
        
        if self.character_detection_mode:
            self.log_message("已切换到字符检测模式 - 专注于检测按键字符内容", "info")
        else:
            self.log_message("已切换到像素检测模式 - 基于像素位置检测", "info")
        
    def perform_keyboard_detection(self, frame):
        """执行键盘检测 - 基于字符内容的检测"""
        try:
            if self.character_detection_mode:
                # 使用字符检测模式
                self._perform_character_detection(frame)
            else:
                # 使用传统像素检测模式
                self._perform_pixel_detection(frame)
                
        except Exception as e:
            self.log_message(f"检测过程中发生错误: {str(e)}", "error")
    
    def _perform_character_detection(self, frame):
        """执行字符检测"""
        from simple_character_detector import SimpleCharacterDetector, KeyErrorType
        
        # 创建字符检测器实例
        if not hasattr(self, 'char_detector'):
            self.char_detector = SimpleCharacterDetector()
        
        # 检测当前帧中的字符
        current_characters = self.char_detector.detect_keyboard_characters(frame)
        
        # 与参考键盘比较
        if self.reference_characters:
            errors = self.char_detector.compare_with_reference(current_characters, self.reference_characters)
            
            # 可视化检测结果
            result_frame = self.char_detector.visualize_character_detection(frame, current_characters, errors)
            
            # 更新显示
            self.display_detection_result(result_frame)
            self.display_camera_frame(frame)
            
            # 输出检测结果
            if errors:
                # 按错误类型分组统计
                error_counts = {}
                for error in errors:
                    error_type = error.error_type.value
                    if error_type not in error_counts:
                        error_counts[error_type] = 0
                    error_counts[error_type] += 1
                
                # 输出统计信息
                total_errors = len(errors)
                self.log_message(f"检测到 {total_errors} 个字符错误:", "warning")
                for error_type, count in error_counts.items():
                    self.log_message(f"  - {error_type}: {count} 个", "warning")
                
                # 输出前几个具体错误
                for i, error in enumerate(errors[:10]):  # 只显示前10个
                    self.log_message(f"  - {error.description} (位置: {error.position})", "error")
                
                if len(errors) > 10:
                    self.log_message(f"  - ... 还有 {len(errors) - 10} 个错误", "warning")
            else:
                self.log_message("✅ 字符检测通过，未发现错误", "success")
                
            # 显示检测到的字符统计
            self.log_message(f"检测到 {len(current_characters)} 个字符按键", "info")
            if current_characters:
                chars = [key.character for key in current_characters]
                self.log_message(f"当前字符: {', '.join(chars[:15])}{'...' if len(chars) > 15 else ''}", "info")
        else:
            self.log_message("请先加载参考键盘图像", "warning")
    
    def _perform_pixel_detection(self, frame):
        """执行传统像素检测"""
        try:
            # 导入改进的检测器
            from improved_keyboard_detector import ImprovedKeyboardDetector, KeyIssueType
            
            # 创建检测器实例
            if not hasattr(self, 'detector'):
                self.detector = ImprovedKeyboardDetector()
                
            # 检测当前帧中的按键（包含旋转校正）
            current_keys, corrected_frame, current_rotation = self.detector.detect_keyboard_keys(frame)
            
            # 记录旋转信息
            if abs(current_rotation) > 1:
                self.log_message(f"检测到图像旋转 {current_rotation:.1f}°，已自动校正", "info")
            
            # 对比键盘（使用校正后的图像）
            issues = self.detector.compare_keyboards(
                self.reference_keys, 
                current_keys, 
                corrected_frame.shape
            )
            
            # 可视化检测结果
            result_frame = self.detector.visualize_detection(corrected_frame, current_keys, issues)
            
            # 更新显示
            self.display_detection_result(result_frame)
            
            # 同时显示原始摄像头图像（用于对比）
            self.display_camera_frame(frame)
            
            # 输出检测结果
            if issues:
                # 按问题类型分组统计
                issue_counts = {}
                for issue in issues:
                    issue_type = issue.issue_type.value
                    if issue_type not in issue_counts:
                        issue_counts[issue_type] = 0
                    issue_counts[issue_type] += 1
                
                # 输出统计信息
                total_issues = len(issues)
                self.log_message(f"检测到 {total_issues} 个问题:", "warning")
                for issue_type, count in issue_counts.items():
                    self.log_message(f"  - {issue_type}: {count} 个", "warning")
                
                # 输出前几个具体问题
                for i, issue in enumerate(issues[:5]):  # 只显示前5个问题
                    issue_msg = f"  - {issue.description} (置信度: {issue.confidence:.2f})"
                    if issue.issue_type in [KeyIssueType.MISSING, KeyIssueType.WRONG_KEY]:
                        self.log_message(issue_msg, "error")
                    else:
                        self.log_message(issue_msg, "warning")
                
                if total_issues > 5:
                    self.log_message(f"  - ... 还有 {total_issues - 5} 个问题", "warning")
            else:
                self.log_message("键盘检测通过 - 所有按键位置正确", "success")
                    
        except Exception as e:
            self.log_message(f"检测过程中出现错误: {str(e)}", "error")
            import traceback
            self.log_message(f"详细错误: {traceback.format_exc()}", "error")
            
    def display_detection_result(self, result_frame):
        """显示检测结果"""
        try:
            # 转换图像格式
            frame_rgb = cv2.cvtColor(result_frame, cv2.COLOR_BGR2RGB)
            pil_image = Image.fromarray(frame_rgb)
            
            # 保存原始PIL图像
            self.result_pil_image = pil_image
            
            # 显示图像
            self._update_result_display()
        except Exception as e:
            self.log_message(f"显示检测结果失败: {str(e)}", "error")
    
    def _update_result_display(self):
        """更新检测结果显示"""
        if not hasattr(self, 'result_pil_image') or self.result_pil_image is None:
            return
            
        # 获取画布尺寸
        canvas_width = self.result_canvas.winfo_width()
        canvas_height = self.result_canvas.winfo_height()
        
        if canvas_width <= 1 or canvas_height <= 1:
            return
            
        # 计算缩放后的图像尺寸
        img_width, img_height = self.result_pil_image.size
        scaled_width = int(img_width * self.result_scale)
        scaled_height = int(img_height * self.result_scale)
        
        # 调整图像大小
        resized_image = self.result_pil_image.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
        
        # 转换为Tkinter格式
        self.result_photo = ImageTk.PhotoImage(resized_image)
        
        # 计算图像在画布中的位置
        x = canvas_width // 2 + self.result_offset_x
        y = canvas_height // 2 + self.result_offset_y
        
        # 清除画布并显示图像
        self.result_canvas.delete("all")
        self.result_canvas.create_image(x, y, image=self.result_photo, anchor=tk.CENTER)
        
        # 添加操作提示
        self.result_canvas.create_text(10, 10, text="鼠标中键: 缩放 | 左键拖拽: 平移 | 右键: 重置", 
                                     anchor=tk.NW, fill="blue", font=("Arial", 8))
    
    def on_result_mousewheel(self, event):
        """检测结果图像鼠标滚轮缩放"""
        if not hasattr(self, 'result_pil_image') or self.result_pil_image is None:
            return
            
        # 缩放因子
        scale_factor = 1.1 if event.delta > 0 else 0.9
        
        # 限制缩放范围
        new_scale = self.result_scale * scale_factor
        if 0.1 <= new_scale <= 5.0:
            self.result_scale = new_scale
            self._update_result_display()
    
    def on_result_mouse_press(self, event):
        """检测结果图像鼠标按下"""
        self.result_drag_start_x = event.x
        self.result_drag_start_y = event.y
        self.result_is_dragging = True
    
    def on_result_mouse_drag(self, event):
        """检测结果图像鼠标拖拽"""
        if not self.result_is_dragging:
            return
            
        # 计算拖拽距离
        dx = event.x - self.result_drag_start_x
        dy = event.y - self.result_drag_start_y
        
        # 更新偏移量
        self.result_offset_x += dx
        self.result_offset_y += dy
        
        # 更新拖拽起始点
        self.result_drag_start_x = event.x
        self.result_drag_start_y = event.y
        
        # 更新显示
        self._update_result_display()
    
    def on_result_mouse_release(self, event):
        """检测结果图像鼠标释放"""
        self.result_is_dragging = False
    
    def on_result_reset_view(self, event):
        """检测结果图像重置视图"""
        self.result_scale = 1.0
        self.result_offset_x = 0
        self.result_offset_y = 0
        self._update_result_display()
        self.log_message("检测结果视图已重置", "info")
    
    def log_message(self, message, level="info"):
        """添加日志消息"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        formatted_message = f"[{timestamp}] {message}\n"
        
        # 添加到队列
        self.log_queue.put((formatted_message, level))
    
    def start_log_updater(self):
        """启动日志更新线程"""
        def update_log():
            while True:
                try:
                    message, level = self.log_queue.get(timeout=0.1)
                    self.log_text.insert(tk.END, message, level)
                    self.log_text.see(tk.END)
                except queue.Empty:
                    pass
                except Exception as e:
                    print(f"日志更新错误: {e}")
        
        log_thread = threading.Thread(target=update_log, daemon=True)
        log_thread.start()
    
    def clear_log(self):
        """清空日志"""
        self.log_text.delete(1.0, tk.END)
        self.log_message("日志已清空", "info")
        
    def run(self):
        """运行应用程序"""
        self.log_message("键盘识别检测系统已启动 v2.0", "info")
        self.log_message("主要功能:", "info")
        self.log_message("  - 字符检测模式：专注于检测按键字符内容，检查员工是否放错按键", "info")
        self.log_message("  - 像素检测模式：基于像素位置的传统检测方法", "info")
        self.log_message("  - 自动摆正参考图像：基于多种算法自动校正旋转角度", "info")
        self.log_message("  - 智能旋转检测：键盘边缘、字符方向、按键排列", "info")
        self.log_message("  - 去除光影干扰：自适应阈值和形态学处理", "info")
        self.log_message("  - 局部特征验证：针对特定区域进行精确检测", "info")
        self.log_message("使用说明:", "info")
        self.log_message("  1. 选择检测模式（推荐使用字符检测模式）", "info")
        self.log_message("  2. 加载参考键盘图像（程序会自动摆正）", "info")
        self.log_message("  3. 启动摄像头", "info")
        self.log_message("  4. 点击'单次检测'进行手动检测", "info")
        self.log_message("  5. 或点击'开始连续检测'进行自动检测", "info")
        self.log_message("图像交互:", "info")
        self.log_message("  - 鼠标中键滚轮：缩放图像（0.1x - 5.0x）", "info")
        self.log_message("  - 左键拖拽：平移图像", "info")
        self.log_message("  - 右键点击：重置视图", "info")
        self.root.mainloop()
        
        # 清理资源
        self.stop_camera()

if __name__ == "__main__":
    app = KeyboardInspector()
    app.run()